#include "MeshFactory.h"
#include "IMesh.h"
#include "assimp.h"
#include "AnimationController.h"
#include "AnimData.h"
#include "AnimNodeData.h"

using namespace Assimp;

MeshFactory::MeshFactory(void)
{
	MeshCreators[MODEL_XMLModel] = &MeshFactory::LoadXMLModel;
	MeshCreators[MODEL_QUAD] = &MeshFactory::LoadQuad;
	MeshCreators[MODEL_BOX] = &MeshFactory::LoadBox;	
}

MeshFactory::~MeshFactory(void)
{
}

IMesh* MeshFactory::LoadAssimpSingleModel(const char* scenePath ,bool cacheLoadedScene,bool KeepModelDateInRam )
{
	assert(scenePath);
	static map<string, IMesh*> iAssimpSingleModelCache;
	IMesh* mesh = iAssimpSingleModelCache[scenePath];
	if(mesh !=NULL)
	{
		return mesh->Clone();
	}
	else
	{
		SceneElements* elem = LoadScene(scenePath ,SceneType::GENERIC,cacheLoadedScene,KeepModelDateInRam);
		assert(elem->Mesh.size() == 1);
		iAssimpSingleModelCache[scenePath] = elem->Mesh[0];
		return iAssimpSingleModelCache[scenePath];
	}	
}

SceneElements* MeshFactory::LoadScene(const char* scenePath ,SceneType sceneType,bool cacheLoadedScene ,bool KeepModelDateInRam )
{		
	SceneElements* elements =  new SceneElements();
	// Create a logger instance 
	DefaultLogger::create("Logger.txt",Logger::VERBOSE);

	// Now I am ready for logging my stuff
	DefaultLogger::get()->info("STARTING");	

	Importer importer;

	  // And have it read the given file with some example postprocessing
	  // Usually - if speed is not the most important aspect for you - you'll 
	  // propably to request more postprocessing than we do in this example.
	  const aiScene* scene = importer.ReadFile( scenePath, 
			aiProcess_LimitBoneWeights		 |
			aiProcess_CalcTangentSpace       | 
			aiProcess_Triangulate            |
			aiProcess_JoinIdenticalVertices  |
			aiProcess_MakeLeftHanded		|
			aiProcess_OptimizeMeshes        |
			aiProcess_FlipUVs				|			
			aiProcess_GenSmoothNormals		|
			aiProcess_FixInfacingNormals
		);
	  
	  // If the import failed, report it
	  if( !scene)
	  {
		DefaultLogger::get()->info("ERRO CANNOT LOAD");	
	  }	
	  else
	  {	
		  struct aiMatrix4x4 trafo;
		  aiIdentityMatrix4(&trafo);	  
		  SceneAnimNode* animNode = CopyNodesWithMeshes(scene,scene->mRootNode,elements ,trafo,NULL,KeepModelDateInRam);		  

		  AnimationController* controller = new AnimationController();
		  for(unsigned i = 0; i < scene->mNumAnimations;i++)
		  {
				aiAnimation* anim = scene->mAnimations[i];
				AnimData* andata = new AnimData();

				if(anim->mName.length ==0)
				{
					andata->mName = string("NONAME");
				}
				else
				{
					andata->mName = string(anim->mName.data);
				}

				andata->mDuration = anim->mDuration;
				andata->mTicksPerSecond = anim->mTicksPerSecond;
				andata->mNumChannels = anim->mNumChannels;				
				andata->mChannels = (AnimNodeData**) malloc(sizeof(AnimNodeData**) * andata->mNumChannels );				
				
				for(unsigned j = 0; j < anim->mNumChannels;j++)
				{			
					aiNodeAnim* odata = anim->mChannels[j] ;

					AnimNodeData * data = new AnimNodeData ();
					andata->mChannels[j] = data; 

					data->mNodeName = odata->mNodeName.data;
					data->mNumPositionKeys = odata->mNumPositionKeys;
					data->mNumRotationKeys = odata->mNumRotationKeys ;
					data->mNumScalingKeys= odata->mNumScalingKeys;

					data->mPostState =  (AnimBehaviour) odata->mPostState;
					data->mPreState  =  (AnimBehaviour) odata->mPreState;

					data->mPositionKeys = (VectorData*) malloc(sizeof(VectorData) * data->mNumPositionKeys );
					for(int k = 0; k < odata->mNumPositionKeys;k++)
					{
						data->mPositionKeys[k].mValue = (XMVECTOR*) _aligned_malloc(sizeof(XMVECTOR),16);
						data->mPositionKeys[k].mTime  = odata->mPositionKeys[k].mTime;						 
						*(data->mPositionKeys[k].mValue) = XMVectorSet(odata->mPositionKeys[k].mValue.x,odata->mPositionKeys[k].mValue.y,odata->mPositionKeys[k].mValue.z,0);							
					}

					data->mScalingKeys= (VectorData*) malloc(sizeof(VectorData) * data->mNumScalingKeys );
					for(int k = 0; k < odata->mNumScalingKeys;k++)
					{
						data->mScalingKeys[k].mValue = (XMVECTOR*) _aligned_malloc(sizeof(XMVECTOR),16);
						data->mScalingKeys[k].mTime = odata->mScalingKeys[k].mTime;						 
						*(data->mScalingKeys[k].mValue) = XMVectorSet(odata->mScalingKeys[k].mValue.x,odata->mScalingKeys[k].mValue.y,odata->mScalingKeys[k].mValue.z,0);							
					}

					data->mRotationKeys= (VectorData*) malloc(sizeof(VectorData) * data->mNumRotationKeys );
					for(int k = 0; k < odata->mNumRotationKeys;k++)
					{
						data->mRotationKeys[k].mValue = (XMVECTOR*) _aligned_malloc(sizeof(XMVECTOR),16);
						data->mRotationKeys[k].mTime = odata->mRotationKeys[k].mTime;						 
						*(data->mRotationKeys[k].mValue) = XMVectorSet(odata->mRotationKeys[k].mValue.x,odata->mRotationKeys[k].mValue.y,odata->mRotationKeys[k].mValue.z,odata->mRotationKeys[k].mValue.w);							
					}					
				}////data loaded				

			    AnimEvaluator* eval = new AnimEvaluator(andata);
				eval->AnimationIndex = i;
				controller->AddAnimation(eval);
		  }

		  for(unsigned i = 0; i < elements->Mesh.size();i++)
		  {
			    if(elements->Mesh[i]->Animated)
				{					
					elements->Mesh[i]->mAnimationController = controller;					
				}
				elements->Mesh[i]->Nodes = Nodes;
		  }
		  nodeSceneMap.clear();		  
		  Nodes.clear();
	  }	

	  // Kill it after the work is done
	  DefaultLogger::kill();

	  return elements;
}


MeshTypeData MeshFactory::GetVertexData(VertexData* outData,UINT** indices,aiMesh* mesh) 
{
	MeshTypeData mType = MeshTypeData::NONE;
	if(mesh->HasPositions())
	{
		if(mesh->HasNormals())
		{		
			if(mesh->HasTextureCoords(0))
			{
				if(mesh->HasTangentsAndBitangents())
				{
					///
					if(mesh->HasBones())
					{
						mType = MeshTypeData::PositionTextureNormalTangentBinormalAnimated;
					}
					else
					{
						mType = MeshTypeData::PositionTextureNormalTangentBinormal;
					}					
				}
				else
				{					
					if(mesh->HasBones())
					{
						mType = MeshTypeData::PositionTextureNormal;
					}
					else
					{
						mType = MeshTypeData::PositionTextureNormal;
					}
				}
			}
			else if(mesh->HasVertexColors(0))
			{
				///
				if(mesh->HasBones())
				{
					assert(false);
				}
				else
				{	
					assert(false);
				}
			}
		}
	}

	if(mType == MeshTypeData::PositionTextureNormal)
	{	
		  outData->positionTextureNormalVertex = (PositionTextureNormalVertex*) malloc(sizeof(PositionTextureNormalVertex) * mesh->mNumVertices);
		  if(mesh->GetNumUVChannels() > 1)
		  {
			  ///FAIL
			  ///ONLY ONE IS USED
		  }
		  for(int j = 0; j < mesh->mNumVertices;j++)
		  {
			  outData->positionTextureNormalVertex ->Position = XMFLOAT3(mesh->mVertices[j].x,mesh->mVertices[j].y,mesh->mVertices[j].z);
			  outData->positionTextureNormalVertex ->Normal = XMFLOAT3(mesh->mNormals[j].x,mesh->mNormals[j].y,mesh->mNormals[j].z);
			  outData->positionTextureNormalVertex->Texture = XMFLOAT2( mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y);
		  }		  	
	}
	else if(mType == MeshTypeData::PositionTextureNormalTangentBinormal)
	{		  
		  outData->positionTextureNormalTangentBinormalVertex = (PositionTextureNormalTangentBinormalVertex*) malloc(sizeof(PositionTextureNormalTangentBinormalVertex) * mesh->mNumVertices);
		  if(mesh->GetNumUVChannels() > 1)
		  {
			  ///FAIL
			  ///ONLY ONE IS USED
		  }
		  for(int j = 0; j < mesh->mNumVertices;j++)
		  {
			  outData->positionTextureNormalTangentBinormalVertex[j].Position = XMFLOAT3(mesh->mVertices[j].x,mesh->mVertices[j].y,mesh->mVertices[j].z);
			  outData->positionTextureNormalTangentBinormalVertex[j].Normal = XMFLOAT3(mesh->mNormals[j].x,mesh->mNormals[j].y,mesh->mNormals[j].z);
			  outData->positionTextureNormalTangentBinormalVertex[j].Texture = XMFLOAT2( mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y);
			  outData->positionTextureNormalTangentBinormalVertex[j].Binormal = XMFLOAT3( mesh->mBitangents[j].x,mesh->mBitangents[j].y,mesh->mBitangents[j].z);
			  outData->positionTextureNormalTangentBinormalVertex[j].Tangent = XMFLOAT3( mesh->mTangents[j].x,mesh->mTangents[j].y,mesh->mTangents[j].z);		  
		  }		  	
	}
	else if(mType == MeshTypeData::PositionTextureNormalTangentBinormalAnimated)
	{
		  outData->positionTextureNormalTangentBinormalAnimatedVertex = (PositionTextureNormalTangentBinormalAnimatedVertex*) malloc(sizeof(PositionTextureNormalTangentBinormalAnimatedVertex) * mesh->mNumVertices);		  
		  for(int j = 0; j < mesh->mNumVertices;j++)
		  {
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Position = XMFLOAT3(mesh->mVertices[j].x,mesh->mVertices[j].y,mesh->mVertices[j].z);
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Normal = XMFLOAT3(mesh->mNormals[j].x,mesh->mNormals[j].y,mesh->mNormals[j].z);
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Texture = XMFLOAT2( mesh->mTextureCoords[0][j].x, mesh->mTextureCoords[0][j].y);
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Binormal = XMFLOAT3( mesh->mBitangents[j].x,mesh->mBitangents[j].y,mesh->mBitangents[j].z);
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Tangent = XMFLOAT3( mesh->mTangents[j].x,mesh->mTangents[j].y,mesh->mTangents[j].z);		
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Weights = XMFLOAT4( 0,0,0,0);		
			  outData->positionTextureNormalTangentBinormalAnimatedVertex[j].Indexes = XMFLOAT4( 0,0,0,0);		
		  }		  	
	}
	else
	{
		assert(false);
	}
	
	UINT* ind = (UINT* ) malloc(sizeof(UINT) *mesh->mNumFaces * 3);
	int it = 0;
	for(int j = 0; j < mesh->mNumFaces;j++)
	{
		if(mesh->mFaces->mNumIndices!=3)
		{
				  ///NOT TRIANGLE !!!
			assert(false);
		}
		ind[it++] = mesh->mFaces[j].mIndices[0];
		ind[it++] = mesh->mFaces[j].mIndices[1];
		ind[it++] = mesh->mFaces[j].mIndices[2];
    }
	*indices = ind;
	return mType;
}

SceneAnimNode* MeshFactory::CopyNodesWithMeshes(const aiScene* scene,aiNode* node, SceneElements* elements, aiMatrix4x4 accTransform,SceneAnimNode* pParent,bool KeepModelDateInRam )
{  	
	SceneAnimNode*  internalNode   = NULL;
	internalNode = nodeSceneMap[node];

	if(internalNode == NULL)
	{
		internalNode = new(16) SceneAnimNode( node->mName.data);
		nodeSceneMap[node] = internalNode;		
		internalNode->index = Nodes.size();
		Nodes.push_back(internalNode);
	}
	else
	{
		internalNode->mName = node->mName.data;
	}
	
	if(pParent != NULL)
		internalNode->mParent = pParent->index;	
	else
		internalNode->mParent  = -1;

    // find the index of the animation track affecting this node, if any			
	for( unsigned int b = 0; b < scene->mNumAnimations; b++)
	{			
		const aiAnimation* currentAnim = scene->mAnimations[b];
		internalNode->animationChannelIndex[b] = -1;
		for( unsigned int a = 0; a < currentAnim->mNumChannels; a++)
		{
			if( currentAnim->mChannels[a]->mNodeName.data == internalNode->mName)
			{
				internalNode->animationChannelIndex[b] = a;
				break;
			}
		}		
	 }  
 
  // copy its transformation  
  aiMatrix4x4 transform = node->mTransformation.Transpose();
  internalNode->mLocalTransform = TOXMMATRIX(transform );
  //internalNode->CalculateGlobalTransform();		
  
  transform = accTransform * transform ;    
  aiString st = node->mName;

  //if node has meshes, create a new scene object for it
  if( node->mNumMeshes > 0)
  {	  
	  for(int i = 0; i < node->mNumMeshes;i++)
	  {
		  IMesh* m = new IMesh();
		  VertexData vd;		  
		  aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
		  UINT* indices;
		  
		  MeshTypeData Mtype = GetVertexData(&vd,&indices,mesh);	      

		  int materialid = mesh->mMaterialIndex;
		  aiMaterial* mat = scene->mMaterials[materialid];
          aiString szPath;
		  char diffuseName[150];

			   //diffuse texture
			if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_DIFFUSE(0), &szPath))
			{
                  strcpy(diffuseName, szPath.data);            
			}
			else
			{
				strcpy(diffuseName,DEFAULTTEXTURE);            
			}
            //specular texture
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_SPECULAR(0), &szPath))
            {
                 //strcpy(tmpmaterial.SpecularTextureName, szPath.data);
            
            }
            //opacity texture
			if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_OPACITY(0), &szPath))
            {
                //strcpy(tmpmaterial.OpacityTextureName, szPath.data);
			
            }
            //emissive texture
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_EMISSIVE(0), &szPath))
            {
				///strcpy(tmpmaterial.EmissiveTextureName, szPath.data);
			
            }
            //shininess texture
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_SHININESS(0), &szPath))
            {
				//strcpy(tmpmaterial.ShininessTextureName, szPath.data);
            
            }
            //light map texture
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_LIGHTMAP(0), &szPath))
            {
				//strcpy(tmpmaterial.LightMapTextureName, szPath.data);
			
		    }
            //normal / height map texture
            bool bHM = false;
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_NORMALS(0), &szPath))
            {
				//strcpy(tmpmaterial.NormalMapTextureName, szPath.data);
			
            }
            if(AI_SUCCESS == aiGetMaterialString(mat, AI_MATKEY_TEXTURE_HEIGHT(0), &szPath))
            {
					//strcpy(tmpmaterial.NormalMapTextureName, szPath.data);            
            }			  			

			XMMATRIX trans = TOXMMATRIX(transform);				

			if(mesh->HasBones())
			{ 				
				vector<std::pair<XMFLOAT4X4,int>> resp = ProcessBones(scene->mRootNode, mesh,vd.positionTextureNormalTangentBinormalAnimatedVertex);
				m->Init(vd,mesh->mNumVertices,Mtype ,indices,mesh->mNumFaces*3,trans,st.data,diffuseName,D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,KeepModelDateInRam );			
				m->BoneMatrix = resp;
				m->Animated = true;			
			}
			else
			{
				m->Init(vd,mesh->mNumVertices,Mtype ,indices,mesh->mNumFaces*3,trans,st.data,diffuseName,D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,KeepModelDateInRam );			
			}		
			m->mMyNode = internalNode->index;
			elements->Mesh.push_back(m);		  
	  }
  }
 
  // continue for all child nodes
  for (int n = 0; n < node->mNumChildren; ++n) {
	    SceneAnimNode* childNode = CopyNodesWithMeshes(scene,node->mChildren[n],elements,transform,internalNode,KeepModelDateInRam);
		internalNode->mChildren.push_back( childNode->index);		
	}
  return internalNode;
}	

vector<std::pair<XMFLOAT4X4,int>> MeshFactory::ProcessBones(aiNode* root, aiMesh* mesh, PositionTextureNormalTangentBinormalAnimatedVertex* vertexData)
{		
		vector<std::pair<XMFLOAT4X4,int>> boneMatrix;
		boneMatrix.resize(mesh->mNumBones);

		////PESOS E INDICES
		vector<vector<aiVertexWeight> > weightsPerVertex(mesh->mNumVertices);
		
		for( unsigned int a = 0; a < mesh->mNumBones; a++)	
		{
			const aiBone* bone = mesh->mBones[a];
			
			aiNode* node = root->FindNode(bone->mName);
			SceneAnimNode* snode = nodeSceneMap[node];
			if(snode  == NULL)
			{
				snode = new(16) SceneAnimNode;
				nodeSceneMap[node] = snode;
				snode->index = Nodes.size();
				Nodes.push_back(snode);
			}
			
			aiMatrix4x4 offtransp = bone->mOffsetMatrix;
			offtransp = offtransp.Transpose();
			std::pair<XMFLOAT4X4,int> pp= std::pair<XMFLOAT4X4,int>(TOXMFLOAT4X4(offtransp),snode->index);
			boneMatrix[a] = pp;

			for( unsigned int b = 0; b < bone->mNumWeights; b++)
			{
				weightsPerVertex[bone->mWeights[b].mVertexId].push_back( aiVertexWeight( a, bone->mWeights[b].mWeight));
			}
		}

		for (unsigned int x = 0; x < mesh->mNumVertices;++x)
		{			
			int size = weightsPerVertex[x].size();
			if(size > 0)
			{
				vertexData[x].Indexes.x = weightsPerVertex[x][0].mVertexId;
				vertexData[x].Weights.x = weightsPerVertex[x][0].mWeight; 
			}
			if(size > 1)
			{
				vertexData[x].Indexes.y = weightsPerVertex[x][1].mVertexId;
				vertexData[x].Weights.y = weightsPerVertex[x][1].mWeight; 
			}
			if(size>2)
			{
				vertexData[x].Indexes.z = weightsPerVertex[x][2].mVertexId;
				vertexData[x].Weights.z = weightsPerVertex[x][2].mWeight; 
			}
			if(size >3)
			{
				vertexData[x].Indexes.w = weightsPerVertex[x][3].mVertexId;
				vertexData[x].Weights.w = weightsPerVertex[x][3].mWeight; 
			}

		}
		return boneMatrix;
}



IMesh* MeshFactory::LoadModel(const char* scenePath ,const char* meshName, MeshTypeData meshType, unsigned char ModelType, bool cacheLoadedModel )
{
	IMesh* mesh; 
	char cacheName[250]; 
	strcpy(cacheName,scenePath);
	strcat(cacheName,meshName);
	if( (mesh  = cache[cacheName]) != NULL)
		return mesh;	
	
	if(MeshCreators[ModelType] != NULL)
	{
		IMesh* mesh = MeshCreators[ModelType](scenePath,meshName ,meshType,cacheLoadedModel );		
		if(cacheLoadedModel)
			cache[cacheName] = mesh;
		return mesh;		
	}	
	return NULL;
}

IMesh* MeshFactory::LoadBox(const char* scenePath ,const char* meshName , MeshTypeData meshType , bool cacheLoadedModel)
{
	VertexData vData;
	int countVertices ;
	countVertices = 24;
	PositionTextureNormalVertex vertices[] =
    {
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) , XMFLOAT3(0,0,0) },
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},

        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},

        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ), XMFLOAT3(0,0,0) },
        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},

        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},

        { XMFLOAT3( -1.0f, -1.0f, -1.0f ), XMFLOAT2( 0.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, -1.0f, -1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, 1.0f, -1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, 1.0f, -1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},

        { XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f ) , XMFLOAT3(0,0,0)},
        { XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f ) , XMFLOAT3(0,0,0)},
    };	
	vData.positionTextureNormalVertex = vertices;

	int countIndices = 36;
	UINT indices[] =
    {
        3,1,0,
        2,1,3,

        6,4,5,
        7,4,6,

        11,9,8,
        10,9,11,

        14,12,13,
        15,12,14,

        19,17,16,
        18,17,19,

        22,20,21,
        23,20,22
    };

	const char* diffuseName = NULL;	
	
	XMMATRIX transf = XMMatrixIdentity();

	IMesh* model ;	
	model = new IMesh();
	model->Init(vData,countVertices,meshType,indices,countIndices,transf ,"BOX",diffuseName,D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST,true);	
	return model;
}


IMesh* MeshFactory::LoadQuad(const char* scenePath ,const char* meshName , MeshTypeData meshType , bool cacheLoadedModel)
{
	VertexData vData;
	int countVertices ;

	countVertices = 4;
	PositionTextureNormalVertex* vertices = (PositionTextureNormalVertex*) malloc(sizeof(PositionTextureNormalVertex) * countVertices );

	{			
			vertices[0].Position = XMFLOAT3(-0.8f,-0.8f,0);			
			vertices[0].Texture = XMFLOAT2(0,0);			
			vertices[0].Normal = XMFLOAT3(0,0,0);

			vertices[1].Position = XMFLOAT3(0.8f,-0.8f,0);			
			vertices[1].Texture = XMFLOAT2(1,0);			
			vertices[1].Normal = XMFLOAT3(0,0,0);

			vertices[2].Position = XMFLOAT3(-0.8f,0.8f,0);			
			vertices[2].Texture = XMFLOAT2(0,1);			
			vertices[2].Normal = XMFLOAT3(0,0,0);

			vertices[3].Position = XMFLOAT3(0.8f,0.8f,0);			
			vertices[3].Texture = XMFLOAT2(1,1);			
			vertices[3].Normal = XMFLOAT3(0,0,0);
	}
	vData.positionTextureNormalVertex = vertices;

	int countIndices = 6;
	UINT* indices= (UINT*) malloc(sizeof(UINT) * countIndices );
	
	{
		indices[0] = 0;
		indices[1] = 1;
		indices[2] = 2;
		indices[3] = 1;
		indices[4] = 3;
		indices[5] = 2;
	}

	const char* diffuseName = NULL;	
	
	XMMATRIX transf = XMMatrixIdentity();

	IMesh* model ;	
	model = new IMesh();
	model->Init(vData,countVertices,meshType,indices,countIndices,transf ,"QUAD",diffuseName,D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST,false);
	
	return model;
}

IMesh* MeshFactory::LoadXMLModel(const char* scenePath ,const char* meshName , MeshTypeData meshType , bool cacheLoadedModel)
{
	static map<string, SCena> iCache;
	SCena cena = iCache[scenePath];
	if(cena.Modelos.size() == 0 )
	{
		SceneParser* parser = new SceneParser();
		cena =  parser->ParseScene(scenePath);			
		iCache[scenePath] = cena;
		delete parser;
	}

	SModelo Lmodel;
	bool found = false;
	for(int i = 0; i < cena.Modelos.size();i++)
	{
		if(strcmp(cena.Modelos[i].ModelName, meshName) == 0)
		{
			Lmodel = cena.Modelos[i];
			found = true;
			break;
		}
	}
	CheckErrorBoolNULL(found);
	
	VertexData vData;
	int countVertices ;

	if(meshType == MeshTypeData::PositionTextureNormal)
	{
		countVertices = Lmodel.Vertices.size();
		PositionTextureNormalVertex* vertices = (PositionTextureNormalVertex*) malloc(sizeof(PositionTextureNormalVertex) * countVertices );

		for(int i = 0; i < countVertices ;i++)
		{
			SVector3 pos = Lmodel.Vertices[i].Position;
			vertices[i].Position = XMFLOAT3(pos.x,pos.y,pos.z);

			SVector2 tex = Lmodel.Vertices[i].TextureCoord;
			vertices[i].Texture = XMFLOAT2(tex.x,tex.y);

			SVector3 norm = Lmodel.Vertices[i].Normal;
			vertices[i].Normal = XMFLOAT3(norm.x,norm.y,norm.z);
		}
		vData.positionTextureNormalVertex = vertices;
	}
	else if(meshType == MeshTypeData::PositionTextureNormalTangentBinormal)
	{
		////NON IMPLEMENTED YET
	}	
	
	int countIndices = Lmodel.Indices.size();
	UINT* indices= (UINT*) malloc(sizeof(UINT) * countIndices );

	for(int i = 0; i < countIndices ;i++)
	{
		indices[i] = Lmodel.Indices[i];
	}

	const char* diffuseName = NULL;
	int countMap = Lmodel.Maps.size();
	for(int i = 0; i < countMap ;i++)
	{
		if(strcmp(Lmodel.Maps[i].MapType,DIFFUSE_MAP)==0)
		{
			diffuseName = Lmodel.Maps[i].Path;
		}
	}		
	
	XMMATRIX sca =  XMMatrixScaling(Lmodel.Transformation.Scale.x,Lmodel.Transformation.Scale.y,Lmodel.Transformation.Scale.z);
	XMMATRIX trans = XMMatrixTranslation(Lmodel.Transformation.Translation.x,Lmodel.Transformation.Translation.y,Lmodel.Transformation.Translation.z);
	XMVECTOR rotation = XMVectorSet(Lmodel.Transformation.Rotation.x,Lmodel.Transformation.Rotation.y,Lmodel.Transformation.Rotation.z,Lmodel.Transformation.Rotation.w);	
	XMMATRIX rot = XMMatrixRotationQuaternion(rotation);	
	//XMMATRIX transf = XMMatrixTranspose( sca * trans * rot );
	XMMATRIX transf = sca * trans * rot ;
	

	IMesh* model ;	
	model = new IMesh();
	model->Init(vData,countVertices,meshType,indices,countIndices,transf ,Lmodel.ModelName,diffuseName,D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST,false);
	
	return model;
}
